﻿using System.Windows.Input;

namespace MvvmFx.Common.ViewModels.Commands
{
    /// <summary>
    /// A class that implements <see cref="ICommand"/> by deriving from <see cref="ViewModelCommand"/>,
    /// and adds the functionality to specify a <see cref="SimpleEventHandler"/> and a <see cref="CanExecuteEventHandler"/>
    /// to invoke for the Execute and CanExecute logic of the command.
    /// </summary>
    /// <example>
    /// <code>
    /// var addDocuments = new DelegateCommand(AddDocuments,
    ///                                        HasDocuments);
    /// </code>
    /// </example>
    public class DelegateCommand : ViewModelCommand
    {
        #region [ EventHandlers ]

        /// <summary>
        /// The SimpleEventHandler type handler.
        /// </summary>
        public delegate void SimpleEventHandler();

        /// <summary>
        /// Can CanExecuteEventHandler type handler.
        /// </summary>
        /// <returns></returns>
        public delegate bool CanExecuteEventHandler();

        #endregion

        #region [ Private Members ]

        /// <summary>
        /// The Execute handler.
        /// </summary>
        private readonly SimpleEventHandler executeHandler;

        /// <summary>
        /// The CanExecute handler
        /// </summary>
        private readonly CanExecuteEventHandler canExecuteHandler;

        #endregion

        #region [ Constructors ]

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateCommand"/> class.
        /// </summary>
        /// <param name="executeHandler">The executed handler to attach for the command.</param>
        public DelegateCommand(SimpleEventHandler executeHandler)
        {
            this.executeHandler = executeHandler;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateCommand"/> class.
        /// </summary>
        /// <param name="executeHandler">The executed handler to attach for the command.</param>
        /// <param name="canExecuteHandler">The can execute handler to attach for the command.</param>
        public DelegateCommand(SimpleEventHandler executeHandler, CanExecuteEventHandler canExecuteHandler)
        {
            this.executeHandler = executeHandler;
            this.canExecuteHandler = canExecuteHandler;
        }

        #endregion

        #region [ Overridden Methods ]

        /// <summary>
        /// Execute the unit of logic for the command.
        /// </summary>
        protected sealed override void OnExecute(object param)
        {
            executeHandler();
        }

        /// <summary>
        /// Determin if the command can execute.
        /// </summary>
        /// <returns>If the command can be executed.</returns>
        protected sealed override bool OnCanExecute(object param)
        {
            if (canExecuteHandler != null)
            {
                return canExecuteHandler();
            }

            return true;
        }

        #endregion
    }
}